package klog

import (
	"fmt"
	"gitee.com/klogsdk/klog-go-sdk/internal/apierr"
	"regexp"
	"time"
)

type iRequestId interface {
	GetRequestId() string
	SetRequestId(string)
}

type iStatusCode interface {
	GetStatusCode() int
	SetStatusCode(int)
}

type IKLogError interface {
	SetErrorResp(ErrorResp)
	GetErrorResp() ErrorResp
}

type mapConverter interface {
	ConvertToMap() map[string]interface{}
}

type NameInfo struct {
	ProjectName string `json:"ProjectName,omitempty"`
	LogPoolName string `json:"LogPoolName,omitempty"`
}

func (o *NameInfo) validate() error {
	if o.ProjectName == "" || o.LogPoolName == "" {
		return apierr.New(RequestOpenAPIBodyOrParamInvalid, "ProjectName or LogPoolName is null", nil)
	}
	return nil
}

type PageInfo struct {
	Page int
	Size int
}

func (p *PageInfo) validate() error {
	if p.Page < 0 || p.Size < 0 {
		return apierr.New(RequestOpenAPIBodyOrParamInvalid, "page or size argument can't less than 0", nil)
	}
	return nil
}

type TimeRangeInfo struct {
	From int64
	To   int64
}

func (o *TimeRangeInfo) validate() error {
	if o.From == 0 || o.To == 0 {
		return apierr.New(RequestOpenAPIBodyOrParamInvalid, "From or To is not set or is zero", nil)
	}
	if o.From > o.To {
		return apierr.New(RequestOpenAPIBodyOrParamInvalid, "From is greater than To", nil)
	}
	return nil
}

type LogInfoReq struct {
	NameInfo
	TimeRangeInfo
	Query        string
	HitsOpen     bool
	Interval     int64
	Offset       int
	Size         int
	SortBy       []map[string]bool
	Aggregations interface{}
}

func NewLogInfoReq(projectName string, logPoolName string, from int64, to int64, query string) *LogInfoReq {
	return &LogInfoReq{
		NameInfo: NameInfo{
			ProjectName: projectName,
			LogPoolName: logPoolName,
		},
		TimeRangeInfo: TimeRangeInfo{
			From: from,
			To:   to,
		}, Query: query,
	}
}

func (o *LogInfoReq) ValidateReq() error {
	if err := o.NameInfo.validate(); err != nil {
		return err
	}
	if err := o.TimeRangeInfo.validate(); err != nil {
		return err
	}
	return nil
}

type ProjectInfo struct {
	ProjectName    string
	IamProjectId   int64
	IamProjectName string
	Region         string
	CreateTime     string
	UpdateTime     string
	Description    string
	Tags           []*TagInfo
	LogPoolNum     int
	Status         string
}

type LogPoolInfo struct {
	NameInfo
	Tags          []*TagInfo
	Partitions    int
	RetentionDays int
	LogPoolId     string
	Description   string
	CreateTime    string
	UpdateTime    string
}

func NewLogPoolInfo(projectName, logPoolName string, partitions, retentionDays int) *LogPoolInfo {
	return &LogPoolInfo{NameInfo: NameInfo{ProjectName: projectName, LogPoolName: logPoolName}, RetentionDays: retentionDays, Partitions: partitions}
}

type TagInfo struct {
	Id    int64
	Key   string
	Value string
}

type ListProjectReq struct {
	PageInfo
	ProjectName string
	Tags        []*TagInfo
	Region      string
}

func (o *ListProjectReq) ValidateReq() error {
	return o.PageInfo.validate()
}

func NewListProjectReq(page, size int) *ListProjectReq {
	return &ListProjectReq{PageInfo: PageInfo{Page: page, Size: size}}
}

type ListLogPoolReq struct {
	PageInfo
	NameInfo
	Tags []*TagInfo
}

type DescribeProjectReq struct {
	ProjectName string
}

func (o *DescribeProjectReq) ValidateReq() error {
	if o.ProjectName == "" {
		return apierr.New(RequestOpenAPIBodyOrParamInvalid, "DescribeProjectReq ProjectName is null", nil)
	}
	return nil
}

type DescribeLogPoolReq struct {
	NameInfo
}

func (o *DescribeLogPoolReq) ValidateReq() error {
	return o.NameInfo.validate()
}

func (o *ListLogPoolReq) ValidateReq() error {
	if err := o.PageInfo.validate(); err != nil {
		return err
	}
	if o.ProjectName == "" {
		return apierr.New(RequestOpenAPIBodyOrParamInvalid, "ListLogPoolReq ProjectName is null", nil)
	}
	return nil
}

type LogPolicyPageInfo struct {
	PageIndex int64 `json:"pageIndex,omitempty"`
	PageSize  int64 `json:"pageSize,omitempty"`
}

func (o *LogPolicyPageInfo) validate() error {
	if o.PageIndex < 0 || o.PageSize < 0 {
		return apierr.New(RequestOpenAPIBodyOrParamInvalid, "DescribeLogPolicyReq PageSize or PageIndex can't less than 0", nil)
	}
	return nil
}

type LogPolicyInfo struct {
	Id              int64                  `json:"id"`
	Name            string                 `json:"name"`
	ProjectName     string                 `json:"projectName"`
	DashboardId     string                 `json:"dashboardId"`
	DashBoardName   string                 `json:"dashBoardName"`
	Queries         []*LogQuery            `json:"queries"`
	ChannelParam    *LogPolicyChannelParam `json:"channelParam"`
	ChannelParams   string                 `json:"channelParams"`
	Condition       string                 `json:"condition"`
	ScheduleType    int64                  `json:"scheduleType"`
	FixInterval     string                 `json:"fixInterval"`
	DayOfWeek       int                    `json:"dayOfWeek"`
	Hour            int                    `json:"hour"`
	CronExpr        string                 `json:"cronExpr"`
	NotifyThreshold int64                  `json:"notifyThreshold"`
	NotifyInterval  int64                  `json:"notifyInterval"`
	Remarks         string                 `json:"remarks"`
	Status          *bool                  `json:"-"`
	Enabled         int                    `json:"enabled"`
	Idc             string                 `json:"idc"`
}

func (o *LogPolicyInfo) setstatus() {
	if o.Status != nil {
		if *o.Status {
			o.Enabled = 1
		} else {
			o.Enabled = 2
		}
	}
}

func (o *LogPolicyInfo) ValidateReq() error {
	if o.ScheduleType < 0 || o.ScheduleType > 4 {
		return apierr.New(RequestOpenAPIBodyOrParamInvalid, "LogPolicyReq ScheduleType can't greater than 4 or less than 0", nil)
	}
	if len(o.Name) < 1 || len(o.Name) > 64 {
		return apierr.New(RequestOpenAPIBodyOrParamInvalid, "LogPolicyReq Name length can't greater than 64 or less than 1", nil)
	}
	nameRegexp := regexp.MustCompile("[^a-z0-9A-Z\\p{Han}-_@#.]")
	if ok := !nameRegexp.MatchString(o.Name); !ok {
		return apierr.New(RequestOpenAPIBodyOrParamInvalid, "LogPolicyReq Name is invalid format", nil)
	}
	o.setstatus()
	return nil
}

type LogPolicyChannelParam struct {
	UsrgrpId     float64 `json:"usrgrpId"`
	UsrgrpName   string  `json:"usrgrpName"`
	ChannelType  float64 `json:"channelType"`
	CallBackUrl  string  `json:"callbackUrl"`
	SmsContent   string  `json:"smsContent"`
	EmailContent string  `json:"emailContent"`
}

type LogQuery struct {
	Id           float64 `json:"id"`
	PolicyId     float64 `json:"policyId" `
	GraphId      float64 `json:"graphId" `
	GraphName    string  `json:"graphName" `
	Query        string  `json:"query" `
	Start        string  `json:"start"`
	End          string  `json:"end"`
	LogPoolName  string  `json:"logPoolName"`
	TimeSpanType string  `json:"timeSpanType"`
}

type DescribeLogPolicyReq struct {
	LogPolicyPageInfo
	Query       string `json:"query"`
	Enabled     int    `json:"enabled"`
	ProjectName string `json:"projectName"`
	DashboardId int64  `json:"dashboardId"`
}

func (o *DescribeLogPolicyReq) ConvertToMap() map[string]interface{} {
	return convertStruct2MapDefault(o)
}

func (o *DescribeLogPolicyReq) ValidateReq() error {
	return o.LogPolicyPageInfo.validate()
}

type RemoveLogPolicyReq struct {
	PolicyIdList []int64 `json:"policyIdList"`
}

type DescribeLogHistoryReq struct {
	LogPolicyPageInfo
	Idc         string `json:"idc"`
	PolicyId    int64  `json:"policyId"`
	Start       int64  `json:"start"`
	End         int64  `json:"end"`
	Query       string `json:"query"`
	ProjectName string `json:"projectName"`
}

func (o *DescribeLogHistoryReq) ConvertToMap() map[string]interface{} {
	return convertStruct2MapDefault(o)
}

type AlarmLogPolicyStatusReq struct {
	PolicyId int64 `json:"policyId"`
	Enabled  int   `json:"enabled"`
}

func NewAlarmLogPolicyStatusReq(enabled bool, policyId int64) *AlarmLogPolicyStatusReq {
	res := &AlarmLogPolicyStatusReq{PolicyId: policyId}
	if enabled {
		res.Enabled = 1
	} else {
		res.Enabled = 2
	}
	return res
}

type AlarmStatisticReq struct {
	PolicyId int64 `json:"policyId"`
	Start    int64 `json:"start"`
	End      int64 `json:"end"`
}

func (o *AlarmStatisticReq) ConvertToMap() map[string]interface{} {
	return convertStruct2MapDefault(o)
}

type DownloadTaskReq struct {
	NameInfo
	TimeRangeInfo
}

func (o *DownloadTaskReq) ValidateReq() error {
	if err := o.NameInfo.validate(); err != nil {
		return err
	}
	if err := o.TimeRangeInfo.validate(); err != nil {
		return err
	}
	return nil
}

type DownloadTask struct {
	NameInfo
	TimeRangeInfo
	DownloadID string
	StartTime  int64
	EndTime    int64
}

type ListDownloadTaskReq struct {
	PageInfo
	NameInfo
}

func (o *ListDownloadTaskReq) ValidateReq() error {
	if err := o.NameInfo.validate(); err != nil {
		return err
	}
	return nil
}

type DownloadUrlReq struct {
	DownloadTask
}

type GetUsageFeeReq struct {
	From    string      `json:"From,omitempty"`
	To      string      `json:"To,omitempty"`
	Targets []*NameInfo `json:"Targets,omitempty"`
	Metrics []string    `json:"Metrics,omitempty"`
}

func (o *GetUsageFeeReq) ValidateReq() error {
	if o.From != "" {
		if _, err := time.Parse(getUsageFeeTimePattern, o.From); err != nil {
			return apierr.New(RequestOpenAPIBodyOrParamInvalid, "pattern of From in GetUsageFeeReq is not like yyyy-MM-dd", nil)
		}
	}
	if o.To != "" {
		if _, err := time.Parse(getUsageFeeTimePattern, o.To); err != nil {
			return apierr.New(RequestOpenAPIBodyOrParamInvalid, "pattern of To in GetUsageFeeReq is not like yyyy-MM-dd", nil)
		}
	}
	return nil
}

type GetUsageReq struct {
	Projects   []string
	TimeSeries []int64
	Data       []*UsageMetricInfo
}

type MonitorDataReq struct {
	Service     string
	ProjectName string
	MetricNames []string
	Period      int
	LogPools    []string
	StartTime   string
	EndTime     string
	PageSize    int
	PageNumber  int
}

type DataHeatReq struct {
	ProjectNames []string
	LogPoolNames []string
}

type IndexTemplateReq struct {
	NameInfo
	FullTextIndex *FullTextIndex
	IndexFields   []*IndexField
	IndexStatus   bool
}

func NewIndexTemplateReq(projectName, logPoolName string, fullTextIndex *FullTextIndex, indexStatus bool) *IndexTemplateReq {
	return &IndexTemplateReq{NameInfo: NameInfo{ProjectName: projectName, LogPoolName: logPoolName}, FullTextIndex: fullTextIndex, IndexStatus: indexStatus}
}

type FullTextIndex struct {
	Chinese   bool
	Lowercase bool
	Separator string
}

type IndexField struct {
	FullTextIndex
	FieldName  string
	FieldType  string
	FieldAlias string
	SubFields  []*IndexField
}

func (o *IndexTemplateReq) ValidateReq() error {
	if err := o.NameInfo.validate(); err != nil {
		return err
	}
	if o.FullTextIndex == nil {
		return apierr.New(RequestOpenAPIBodyOrParamInvalid, "FullTextIndex in IndexTemplate is null", nil)
	}
	if len(o.IndexFields) > 0 {
		for _, indexField := range o.IndexFields {
			if !sliceContains(supportIndexType, indexField.FieldType) {
				return apierr.New(RequestOpenAPIBodyOrParamInvalid, fmt.Sprintf("your IndexFieldType:[%s] is unsupported, We only support:%+v", indexField.FieldType, supportIndexType), nil)
			}
		}
	}
	return nil
}

type DashboardInfo struct {
	DashboardId   int64
	DashboardName string
	ProjectName   string
	Charts        []*ChartInfo
	CreateTime    string
	UpdateTime    string
}

type ListDashboardsReq struct {
	PageInfo
	DashboardInfo
}

func (o *ListDashboardsReq) ValidateReq() error {
	if err := o.PageInfo.validate(); err != nil {
		return err
	}
	if o.ProjectName == "" {
		return apierr.New(RequestOpenAPIBodyOrParamInvalid, "ListDashboardsReq ProjectName is null", nil)
	}
	return nil
}

type ChartIdInfo struct {
	ChartId *int64
}

type DeleteDashboardReq struct {
	DashboardId *int64
}

type DescribeDashboardReq struct {
	DashboardId *int64
}

type UpdateDashboardReq struct {
	DashboardId   *int64
	DashboardName string
	ProjectName   string
	Charts        []*ChartInfo
}

func (o *UpdateDashboardReq) ValidateReq() error {
	if o.DashboardId == nil {
		return apierr.New(RequestOpenAPIBodyOrParamInvalid, "dashboardId is nil", nil)
	}
	if o.Charts == nil || len(o.Charts) == 0 {
		return apierr.New(RequestOpenAPIBodyOrParamInvalid, "UpdateDashboardReq charts is nil", nil)
	}
	return nil
}

type ChartInfo struct {
	DashboardId *int64           `json:"DashboardId"`
	ChartName   string           `json:"ChartName"`
	ChartType   string           `json:"ChartType"`
	Search      *ChartSearchInfo `json:"Search"`
	CreateTime  string           `json:"CreateTime"`
	UpdateTime  string           `json:"UpdateTime"`
	Display     string           `json:"Display"`
}

type ChartSearchInfo struct {
	LogPoolName string `json:"LogPoolName"`
	TimeRange   string `json:"TimeRange"`
	Query       string `json:"Query"`
}

type openAPIErrorResp struct {
	RequestId string
	Error     struct {
		Code    string
		Message string
		Type    string
	}
}

func (o *openAPIErrorResp) convert2KlogResp() ErrorResp {
	return ErrorResp{ErrorCode: o.Error.Code, ErrorMessage: o.Error.Message, requestId: o.RequestId}
}

func (o *openAPIErrorResp) hasError() bool {
	return o.Error.Code != "" || o.Error.Message != ""
}

type ErrorResp struct {
	ErrorCode    string `json:"ErrorCode,omitempty"`
	ErrorMessage string `json:"ErrorMessage,omitempty"`
	requestId    string
	statusCode   int
}

func (o *ErrorResp) GetErrorResp() ErrorResp {
	return *o
}

func (o *ErrorResp) SetErrorResp(resp ErrorResp) {
	*o = resp
}

func (o ErrorResp) GetRequestId() string {
	return o.requestId
}

func (o ErrorResp) GetStatusCode() int {
	return o.statusCode
}

func (o *ErrorResp) SetStatusCode(statusCode int) {
	o.statusCode = statusCode
}

func (o *ErrorResp) SetRequestId(requestId string) {
	o.requestId = requestId
}

func (o *ErrorResp) HasError() bool {
	return o.ErrorCode != "" || o.ErrorMessage != ""
}

type LogInfoResp struct {
	ErrorResp
	Total        int64
	Count        int64
	HasSql       bool
	Logs         []map[string]interface{}
	Keys         []string
	Histogram    []*LogHistogram
	KeyValues    map[string][]interface{}
	Aggregations map[string]interface{}
}

type LogHistogram struct {
	Key      string
	LogCount int64
}

type ListRespInfo struct {
	Total int64
	Count int64
}

type ListProjectResp struct {
	ErrorResp
	ListRespInfo
	Projects []*ProjectInfo
}

type ListLogPoolResp struct {
	ErrorResp
	NameInfo
	ListRespInfo
	LogPools []*LogPoolInfo
}

type UserInfoResp struct {
	ErrorResp
	UserId     string
	UserStatus int
}

type DescribeProjectResp struct {
	ErrorResp
	ProjectInfo
}

type DescribeLogPoolResp struct {
	ErrorResp
	LogPoolInfo
}

type IndexTemplateResp struct {
	ErrorResp
	NameInfo
	FullTextIndex *FullTextIndex
	IndexFields   []*IndexField
	IndexStatus   bool
}

type IamProjectInfo struct {
	ProjectId   int64
	ProjectName string
	ProjectDesc string
	Status      int
	CreateTime  string
	Krn         string
}

type ListIamProjectsResp struct {
	ErrorResp
	Total       int64
	ProjectList []*IamProjectInfo
}

type ListTagKeyResp struct {
	ErrorResp
	ListRespInfo
	Keys []string
}

type ListTagValuesResp struct {
	ErrorResp
	ListRespInfo
	Tags []*TagInfo
}

type ListDownloadTaskResp struct {
	ErrorResp
	ListRespInfo
	Downloads []*DownloadTask
}

type DownloadUrlInfo struct {
	TimeRangeInfo
	Url      string
	FileName string
	Status   string
	Size     float64
	SizeUnit string
}

type DownloadUrlsResp struct {
	ErrorResp
	Urls []*DownloadUrlInfo
}

type GetUsageFeeResp struct {
	ErrorResp
	SumPrice float64
	Data     []*UsageMetricInfo
}

type UsageMetricInfo struct {
	MetricName     string
	YesterdayUsage int64
	DayToDayRatio  string
	Output         []int64
	Unit           string
	Price          float64
	SpecialMetric  []*SpecialMetricInfo
}

type SpecialMetricInfo struct {
	Code  string
	Value int64
}

type GetTokenResp struct {
	ErrorResp
	Token    string
	ExpireAt int64
}

type GetUsageResp struct {
	ErrorResp
	Projects   []string
	TimeSeries []int64
	Data       []*UsageMetricInfo
}

type MonitorDataResp struct {
	ErrorResp
	TotalCount int
	PageSize   int
	PageNumber int
	DataPoints []*MonitorDataPoints
}

type MonitorDataPoints struct {
	MetricName string
	Points     []*MonitorDataPoint
}

type MonitorDataPoint struct {
	Keys   *MonitorDataKeyValue
	Values [][]int
}

type MonitorDataKeyValue struct {
	LogPool string
	Project string
}

type DataHeatResp struct {
	ErrorResp
	ProjectNames []string
	LogPoolNames []string
	HeatMetrics  []*DataHeatMetricInfo
}

type DataHeatMetricInfo struct {
	MetricName string
	ItemType   string
	Metrics    []*DataHeatItemMetric
}

type DataHeatItemMetric struct {
	Name    string
	Value   string
	Percent string
}

type LogPolicyResp struct {
	ErrorResp
	Status     int         `json:"status"`
	Message    string      `json:"message"`
	TotalCount int         `json:"totalCount"`
	Data       interface{} `json:"data"`
}

// type DescribeLogPolicyResp struct {
// 	LogPolicyResp
// 	Data struct {
// 		Code          string           `json:"code"`
// 		LogPolicyList []*LogPolicyInfo `json:"logPolicyList,omitempty"`
// 		TotalCount    int64            `json:"totalCount"`
// 		Message       string           `json:"message"`
// 	} `json:"data"`
// }
//
// type DescribeLogHistoryResp struct {
// 	LogPolicyResp
// 	Data []*LogHistory `json:"data"`
// }

type LogHistory struct {
	Id            float64 `json:"id"`
	PolicyId      float64 `json:"policyId"`
	ProjectName   string  `json:"projectName"`
	LogPoolName   string  `json:"logPoolName"`
	DashboardId   string  `json:"dashboardId" `
	DashboardName string  `json:"dashboardName"`
	Name          string  `json:"alertName" `
	ExecuteTime   float64 `json:"executeTime" `
	Condition     string  `json:"condition" `
	NotifyStatus  string  `json:"notifyStatus"`
	Status        string  `json:"status" `
	IsTrigger     bool    `json:"isTrigger"`
	Reason        string  `json:"reason"`
	CreateTime    float64 `json:"createtime"`
}

// type DescribeAlertStatisticsResp struct {
// 	LogPolicyResp
// 	Data []*LogStatistics `json:"data,omitempty"`
// }

type LogStatistics struct {
	AlarmCount  int64  `json:"alarmCount"`
	NotifyCount int64  `json:"notifyCount"`
	AlarmDod    string `json:"alarmDod"`
	NofityDod   string `json:"notifyDod"`
}

type ListDashboardResp struct {
	ErrorResp
	ListRespInfo
	Dashboards []*DashboardInfo
}

type DescribeDashboardResp struct {
	ErrorResp
	DashboardInfo
}

type DashboardIdResp struct {
	ErrorResp
	DashboardId *int64
}

type ChartIdResp struct {
	ErrorResp
	ChartIdInfo
}

type UserGroupResp struct {
	ErrorResp
	UserGrpList []*UserGrpList `json:"userGrpList"`
	TotalCount  int            `json:"totalCount"`
}

type UserGrpList struct {
	UsrGrpID  int    `json:"usrGrpId"`
	Name      string `json:"name"`
	UserCount int    `json:"userCount"`
}
